package pl.com.sthaether.mc.engine.data;

import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.shape.Path;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.scene.transform.Scale;
import javafx.scene.transform.Translate;
import pl.com.sthaether.mc.config.MCCurrentState;
import pl.com.sthaether.mc.main.toolbar.MCToolbar;

import java.util.*;

public class MCMapData {

    public static final double LINE_SHIFT = 20;
    public static final double SCALE = 0.03;
    public static int currentLine = 1;


    private Text mapName;
    private Text cartogramLegendText;
    private Text cartodiagramLegendText;
    private Group dataGroup;
    private Group textGroup;
    private Group shapesGroup;
    private Group infoGroup;
    private Group seriesGroup;

    private final Group mapGroup;
    private MCCartogramColorRange cartogramColorRange;
    private List<MCSeriesColor> cartodiagramSeries;
    private Map<String, MCMapDataObject> objectsMap;

    public MCMapData(Group mapGroup) {

        this.dataGroup = new Group();
        this.textGroup = new Group();
        this.shapesGroup = new Group();
        this.infoGroup = new Group();
        this.mapGroup = mapGroup;
        this.seriesGroup = new Group();
        this.cartodiagramSeries = new ArrayList<>();
        this.mapName = new Text("MAP NAME");
        this.cartogramLegendText = new Text("LEGEND1");
        this.cartodiagramLegendText = new Text("LEGEND2");
        this.mapGroup.getChildren().add(this.shapesGroup);
        this.mapGroup.getChildren().add(this.dataGroup);
        this.mapGroup.getChildren().add(this.textGroup);
        this.mapGroup.getChildren().add(this.infoGroup);
        this.cartogramColorRange = new MCCartogramColorRange();
        this.objectsMap = new HashMap<>();
    }


    public Map<String, MCMapDataObject> getObjectsMap() {
        return objectsMap;
    }

    public Map<String, MCMapDataObject> addMapObject(MCMapDataObject object) {
        objectsMap.put(object.getName(), object);
        for (Path p : object.getPathList()) {
            shapesGroup.getChildren().add(p);
        }
        textGroup.getChildren().add(object.getText());

        return objectsMap;
    }

    public MCMapDataObject getMapObject(String name) {
        return objectsMap.get(name);
    }

    public boolean changeObjectName(String nameFrom, String nameTo) {
        if (containsObject(nameFrom)) {
            MCMapDataObject obj = objectsMap.get(nameFrom);
            objectsMap.remove(nameFrom);
            obj.setName(nameTo);
            objectsMap.put(nameTo, obj);
            return true;
        } else {
            return false;
        }
    }

    public boolean changeObjectColor(String object, Color color) {
        if (objectsMap.containsKey(object)) {
            objectsMap.get(object).setObjectColor(color);
            return true;
        }
        return false;
    }

    public void autoColorByValues() {
        for (MCMapDataObject object : objectsMap.values()) {
            object.setObjectColor(cartogramColorRange.getCartogramColor(object.getObjectValue()));
        }
    }

    public MCCartogramColorRange getCartogramColorRange() {
        return cartogramColorRange;
    }

    public void setCartogramColorRange(MCCartogramColorRange cartogramColorRange) {
        this.cartogramColorRange = cartogramColorRange;
    }

    public boolean containsObject(String name) {
        return objectsMap.containsKey(name);
    }

    public Group getMapGroup() {
        return mapGroup;
    }

    public Group getDataGroup() {
        return dataGroup;
    }

    public Group getShapesGroup() {
        return shapesGroup;
    }

    public Group getInfoGroup() {
        return infoGroup;
    }

    public Group getTextGroup() {
        return textGroup;
    }

    public void updateInfoGroup(double endX, double endY, double startX) {

        this.mapName.getTransforms().add(new Translate(0.9 * (endX - startX) * -30, 0));
        this.infoGroup.getChildren().add(this.mapName);
        this.infoGroup.getTransforms().add(new Translate(endX, endY));
        this.infoGroup.getTransforms().add(new Scale(SCALE, -SCALE));
    }

    public Group getSeriesGroup() {
        return seriesGroup;
    }

    public void updateLegend() {
        currentLine = 1;
        this.infoGroup.getChildren().remove(seriesGroup);
        this.seriesGroup = new Group();
        this.infoGroup.getChildren().add(this.seriesGroup);

        Text title;

        if (MCCurrentState.getInstance().getCurrentMap().getData().getCartogramColorRange().getAll().size() > 0) {
            this.cartogramLegendText.getTransforms().clear();
            this.cartogramLegendText.getTransforms().add(new Translate(0, LINE_SHIFT * currentLine + 12));
            this.seriesGroup.getChildren().add(this.cartogramLegendText);
            currentLine++;
            for (MCColorRange c : MCCurrentState.getInstance().getCurrentMap().getData().getCartogramColorRange().getAll()) {
                Rectangle rec = new Rectangle(0, 0, 14, 14);
                rec.getTransforms().add(new Translate(0, LINE_SHIFT * currentLine));
                rec.setFill(c.getColor());
                this.seriesGroup.getChildren().add(rec);
                title = new Text(c.getFrom() + " - " + c.getTo());
                title.getTransforms().add(new Translate(16, LINE_SHIFT * currentLine + 12));
                this.seriesGroup.getChildren().add(title);
                currentLine++;
            }
            currentLine++;
        }


        if (MCCurrentState.getInstance().getCurrentMap().getData().getCartodiagramSeries().size() > 1) {
            this.cartodiagramLegendText.getTransforms().clear();
            this.cartodiagramLegendText.getTransforms().add(new Translate(0, LINE_SHIFT * currentLine + 12));
            this.seriesGroup.getChildren().add(this.cartodiagramLegendText);
            currentLine++;
            for (MCSeriesColor c : MCCurrentState.getInstance().getCurrentMap().getData().getCartodiagramSeries()) {
                if (c.getName() == null || c.getName().equals("Add") || c.getName().isEmpty()) {
                    continue;
                }
                Rectangle rec = new Rectangle(0, 0, 14, 14);
                rec.getTransforms().add(new Translate(0, LINE_SHIFT * currentLine));
                rec.setFill(c.getColor());
                this.seriesGroup.getChildren().add(rec);
                title = new Text(c.getName());
                title.getTransforms().add(new Translate(16, LINE_SHIFT * currentLine + 12));
                this.seriesGroup.getChildren().add(title);
                currentLine++;
            }
        }

    }

    public Text getMapName() {
        return mapName;
    }

    public Text getCartogramLegendText() {
        return cartogramLegendText;
    }

    public Text getCartodiagramLegendText() {
        return cartodiagramLegendText;
    }

    public List<MCSeriesColor> getCartodiagramSeries() {
        return cartodiagramSeries;
    }

    public void updateMapObjectsSeries() {
        for (MCMapDataObject o : objectsMap.values()) {
            for (Map.Entry<String, DoubleProperty> n : new HashSet<>(o.getChartData().entrySet())) {
                boolean notToDelete = false;
                for (MCSeriesColor c : this.cartodiagramSeries) {
                    if (c.getName() != null && !c.getName().equals("Add") && !c.getName().isEmpty() && n.getKey().equals(c.getName())) {
                        notToDelete = true;
                    }
                }
                if (!notToDelete) {
                    o.getChartData().remove(n.getKey());
                }
            }
            for (MCSeriesColor c : this.cartodiagramSeries) {
                if (!o.getChartData().containsKey(c.getName()) && c.getName() != null && !c.getName().equals("Add") && !c.getName().isEmpty()) {
                    o.getChartData().put(c.getName(), new SimpleDoubleProperty());
                }
            }
        }
        MCToolbar.getInstance().getTable().updateData();
    }

    public void setCartodiagramSeries(List<MCSeriesColor> cartodiagramSeries) {
        this.cartodiagramSeries = cartodiagramSeries;
    }
}
